#ifndef _UTIL_HPP
#define	_UTIL_HPP

#include "Types.hpp"

template<typename Type,uint NUM_ELEMENTS>
class Myvec
{

public:
  Myvec():data_(new Type[NUM_ELEMENTS])
  {
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]=0;
  }
  ~Myvec(){delete [] data_;}
  Myvec(const Myvec<Type,NUM_ELEMENTS>& s)
  {
    delete [] data_;
    data_ = new Type[NUM_ELEMENTS];
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]=s.data_[i];
  }
  Myvec& operator=(const Myvec<Type,NUM_ELEMENTS>& s)
  {
    delete [] data_;
    data_ = new Type[NUM_ELEMENTS];
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]=s.data_[i];
    return *this;
  }

  Myvec& operator+=(const Myvec<Type,NUM_ELEMENTS>& s)
  {
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]+=s.data_[i];
    return *this;
  }
  
  Myvec& operator+=(const Type& s)
  {
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]+=s;
    return *this;
  }

  Myvec& operator-=(const Myvec<Type,NUM_ELEMENTS>& s)
  {
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]-=s.data_[i];
    return *this;
  }
  
  Myvec& operator-=(const Type& s)
  {
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]-=s;
    return *this;
  }
  
  Myvec& operator*=(const Myvec<Type,NUM_ELEMENTS>& s)
  {
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]*=s.data_[i];
    return *this;
  }
  
  Myvec& operator*=(const Type& s)
  {
    for(uint i=0;i<NUM_ELEMENTS;++i)
      data_[i]*=s;
    return *this;
  }

  inline Type& operator()(uint component){return data_[component];}
  
  template<typename T1,typename T2,uint NUM>
  friend auto operator+(const Myvec<T1,NUM>& a,const Myvec<T2,NUM>& b)->Myvec<decltype(a.data_[0]+b.data_[0]),NUM>;

  template<typename T1,typename T2,uint NUM>
  friend auto operator+(const T1& s,const Myvec<T2,NUM>& b)->Myvec<decltype(s+b.data_[0]),NUM>;

  template<typename T1,typename T2,uint NUM>
  friend auto operator+(const Myvec<T2,NUM>& b,const T1& s)->Myvec<decltype(s+b.data_[0]),NUM>;

  template<typename T1,typename T2,uint NUM>
  friend auto operator-(const Myvec<T1,NUM>& a,const Myvec<T2,NUM>& b)->Myvec<decltype(a.data_[0]+b.data_[0]),NUM>;
				 
  template<typename T1,typename T2,uint NUM>
  friend auto operator-(const T1& s,const Myvec<T2,NUM>& b)->Myvec<decltype(s+b.data_[0]),NUM>;

  template<typename T1,typename T2,uint NUM>
  friend auto operator-(const Myvec<T2,NUM>& b,const T1& s)->Myvec<decltype(s+b.data_[0]),NUM>;

  template<typename T1,typename T2,uint NUM>
  friend auto operator*(const Myvec<T1,NUM>& a,const Myvec<T2,NUM>& b)->decltype(a.data_[0]+b.data_[0]);

  template<typename T1,typename T2,uint NUM>
  friend auto operator*(const T1& s,const Myvec<T2,NUM>& b)->Myvec<decltype(s*b.data_[0]),NUM>;

  template<typename T1,typename T2,uint NUM>
  friend auto operator*(const Myvec<T2,NUM>& b,const T1& s)->Myvec<decltype(s*b.data_[0]),NUM>;
private:
  Type* data_;
};

template<typename T1,typename T2,uint NUM>
auto operator+(const Myvec<T1,NUM>& a,const Myvec<T2,NUM>& b)->Myvec<decltype(a.data_[0]+b.data_[0]),NUM>
{
  Myvec<decltype(a.data_[0]+b.data_[0]),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=a.data_[i]+b.data_[i];
  return tmp;
}

template<typename T1,typename T2,uint NUM>
auto operator+(const T1& s, const Myvec<T2,NUM>& b)->Myvec<decltype(s+b.data_[0]),NUM>
{
  Myvec<decltype(b.data_[0]+s),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=s+b.data_[i];
  return tmp;
}

template<typename T1,typename T2,uint NUM>
auto operator+(const Myvec<T2,NUM>& b,const T1& s)->Myvec<decltype(s+b.data_[0]),NUM>
{
  Myvec<decltype(b.data_[0]+s),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=s+b.data_[i];
  return tmp;
}

template<typename T1,typename T2,uint NUM>
auto operator-(const Myvec<T1,NUM>& a,const Myvec<T2,NUM>& b)->Myvec<decltype(a.data_[0]+b.data_[0]),NUM>
{
  Myvec<decltype(a.data_[0]+b.data_[0]),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=a.data_[i]-b.data_[i];
  return tmp;
}


template<typename T1,typename T2,uint NUM>
auto operator-(const Myvec<T2,NUM>& b,const T1& s)->Myvec<decltype(s+b.data_[0]),NUM>
{
  Myvec<decltype(b.data_[0]+s),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=b.data_[i]-s;
  return tmp;
}


template<typename T1,typename T2,uint NUM>
auto operator-(const T1& s, const Myvec<T2,NUM>& b)->Myvec<decltype(s+b.data_[0]),NUM>
{
  Myvec<decltype(b.data_[0]+s),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=s-b.data_[i];
  return tmp;
}

template<typename T1,typename T2,uint NUM>
auto operator*(const Myvec<T1,NUM>& a,const Myvec<T2,NUM>& b)->decltype(a.data_[0]+b.data_[0])
{
  auto tmp=a.data_[0]+b.data_[0];
  for(uint i=1;i<NUM;++i)
    tmp+=a.data_[i]*b.data_[i];
  return tmp;
}

template<typename T1,typename T2,uint NUM>
auto operator*(const T1& s,const Myvec<T2,NUM>& b)->Myvec<decltype(s*b.data_[0]),NUM>
{
  Myvec<decltype(s*b.data_[0]),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=s*b.data_[i];
  return tmp;
}

template<typename T1,typename T2,uint NUM>
auto operator*(const Myvec<T2,NUM>& b,const T1& s)->Myvec<decltype(s*b.data_[0]),NUM>
{
  Myvec<decltype(s*b.data_[0]),NUM> tmp;
  for(uint i=0;i<NUM;++i)
    tmp.data_[i]=s*b.data_[i];
  return tmp;
}

typedef Myvec<real,4> real4;
typedef Myvec<real,3> real3;

typedef Myvec<int,4> int4;
typedef Myvec<int,3> int3;
#endif	// _UTIL_HPP 
